From 037b1435ae5dc094f0d614b2992e414ce835c3e3 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 9 Mar 2013 23:03:38 -0500 Subject: [PATCH] window: Allow theme control over window buttons Add a style property to control the presence and order of window buttons. We allow buttons at the left and right side, they can be specified like this: icon,close:minimize,maximize. Also, change the default button layout back to have just a close button on the right, use icons in buttons, and set style classes on the buttons, to allow better theming. --- gtk/gtkwindow.c | 205 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 162 insertions(+), 43 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index a6bfa201d4..ade610d221 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1025,6 +1025,13 @@ gtk_window_class_init (GtkWindowClass *klass) /* Style properties. */ + gtk_widget_class_install_style_property (widget_class, + g_param_spec_string ("decoration-button-layout", + P_("Decorated button layout"), + P_("Decorated button layout"), + ":close", + GTK_PARAM_READABLE)); + gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("resize-grip-width", P_("Width of resize grip"), @@ -3582,6 +3589,36 @@ icon_list_from_theme (GtkWidget *widget, return list; } +static void +set_title_icon (GtkWindow *window, GList *list) +{ + GtkWindowPrivate *priv = window->priv; + + if (priv->title_icon && list != NULL) + { + GdkPixbuf *pixbuf, *best; + GList *l; + + best = NULL; + for (l = list; l; l = l->next) + { + pixbuf = list->data; + if (gdk_pixbuf_get_width (pixbuf) <= 20) + { + best = g_object_ref (pixbuf); + break; + } + } + + if (best == NULL) + best = gdk_pixbuf_scale_simple (GDK_PIXBUF (list->data), 20, 20, GDK_INTERP_BILINEAR); + + gtk_image_set_from_pixbuf (GTK_IMAGE (priv->title_icon), best); + g_object_unref (best); + + gtk_widget_show (priv->title_icon); + } +} static void gtk_window_realize_icon (GtkWindow *window) @@ -3643,13 +3680,14 @@ gtk_window_realize_icon (GtkWindow *window) { icon_list = icon_list_from_theme (widget, default_icon_name); info->using_default_icon = TRUE; - info->using_themed_icon = TRUE; + info->using_themed_icon = TRUE; } info->realized = TRUE; gdk_window_set_icon_list (gtk_widget_get_window (widget), icon_list); - + set_title_icon (window, icon_list); + if (info->using_themed_icon) { GtkIconTheme *icon_theme; @@ -4867,39 +4905,138 @@ update_window_buttons (GtkWindow *window) { GtkWindowPrivate *priv = window->priv; - if (priv->client_decorated) + if (priv->decorated && + priv->client_decorated && + priv->title_box != NULL) { - if (priv->title_box != NULL) - gtk_widget_show (priv->title_box); + gchar *layout_desc; + gchar **tokens, **t; + gint i, j; + GdkPixbuf *icon = NULL; - if (priv->title_min_button != NULL) + if (priv->title_icon) { - if (priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) - gtk_widget_show (priv->title_min_button); - else - gtk_widget_hide (priv->title_min_button); + icon = gtk_image_get_pixbuf (GTK_IMAGE (priv->title_icon)); + if (icon) + g_object_ref (icon); + gtk_widget_destroy (priv->title_icon); + priv->title_icon = NULL; } - - if (priv->title_max_button != NULL) + if (priv->title_min_button) + { + gtk_widget_destroy (priv->title_min_button); + priv->title_min_button = NULL; + } + if (priv->title_max_button) { - if (priv->resizable && - priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) - gtk_widget_show (priv->title_max_button); - else - gtk_widget_hide (priv->title_max_button); + gtk_widget_destroy (priv->title_max_button); + priv->title_max_button = NULL; } + if (priv->title_close_button) + { + gtk_widget_destroy (priv->title_close_button); + priv->title_close_button = NULL; + } + + gtk_widget_style_get (GTK_WIDGET (window), + "decoration-button-layout", &layout_desc, + NULL); - if (priv->title_close_button != NULL) + tokens = g_strsplit (layout_desc, ":", 2); + if (tokens) { - if (priv->deletable && - priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) - gtk_widget_show_all (priv->title_close_button); - else - gtk_widget_hide (priv->title_close_button); + for (i = 0; i < 2; i++) + { + if (tokens[i] == NULL) + continue; + + t = g_strsplit (tokens[i], ",", -1); + for (j = 0; t[j]; j++) + { + GtkWidget *button = NULL; + + if (strcmp (t[j], "icon") == 0) + { + button = gtk_image_new (); + gtk_widget_set_size_request (button, 20, 20); + gtk_widget_show (button); + if (icon != NULL) + { + gtk_image_set_from_pixbuf (GTK_IMAGE (button), icon); + g_object_unref (icon); + } + else + gtk_widget_hide (button); + + priv->title_icon = button; + } + else if (strcmp (t[j], "minimize") == 0 && + priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) + { + button = gtk_button_new (); + gtk_container_add (GTK_CONTAINER (button), + gtk_image_new_from_icon_name ("window-minimize", GTK_ICON_SIZE_MENU)); + gtk_style_context_add_class (gtk_widget_get_style_context (button), "window-minimize-button"); + gtk_widget_set_can_focus (button, FALSE); + gtk_widget_show_all (button); + g_signal_connect (button, "clicked", + G_CALLBACK (gtk_window_title_min_clicked), window); + priv->title_min_button = button; + } + else if (strcmp (t[j], "maximize") == 0 && + priv->resizable && + priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) + { + GdkWindow *win; + gboolean maximized; + const gchar *icon_name; + + win = gtk_widget_get_window (GTK_WIDGET (window)); + if (win != NULL) + maximized = gdk_window_get_state (win) & GDK_WINDOW_STATE_MAXIMIZED; + else + maximized = FALSE; + icon_name = maximized ? "window-restore" : "window-maximize"; + button = gtk_button_new (); + gtk_container_add (GTK_CONTAINER (button), + gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU)); + gtk_style_context_add_class (gtk_widget_get_style_context (button), "window-maximize-button"); + gtk_widget_set_can_focus (button, FALSE); + gtk_widget_show_all (button); + g_signal_connect (button, "clicked", + G_CALLBACK (gtk_window_title_max_clicked), window); + priv->title_max_button = button; + } + else if (strcmp (t[j], "close") == 0 && + priv->deletable && + priv->gdk_type_hint == GDK_WINDOW_TYPE_HINT_NORMAL) + { + button = gtk_button_new (); + gtk_container_add (GTK_CONTAINER (button), + gtk_image_new_from_icon_name ("window-delete", GTK_ICON_SIZE_MENU)); + gtk_style_context_add_class (gtk_widget_get_style_context (button), "window-close-button"); + gtk_widget_set_can_focus (button, FALSE); + gtk_widget_show_all (button); + g_signal_connect (button, "clicked", + G_CALLBACK (gtk_window_title_close_clicked), window); + priv->title_close_button = button; + } + + if (button) + { + if (i == 0) + gtk_header_bar_pack_start (GTK_HEADER_BAR (priv->title_box), button); + else + gtk_header_bar_pack_end (GTK_HEADER_BAR (priv->title_box), button); + } + } + g_strfreev (t); + } + g_strfreev (tokens); } + g_free (layout_desc); - if (priv->title_label != NULL) - gtk_widget_show (priv->title_label); + gtk_widget_show (priv->title_box); } else { @@ -4961,24 +5098,6 @@ create_decoration (GtkWidget *widget) title = get_default_title (); gtk_header_bar_set_title (GTK_HEADER_BAR (priv->title_box), title); - priv->title_min_button = gtk_button_new_with_label ("_"); - gtk_widget_set_can_focus (priv->title_min_button, FALSE); - gtk_header_bar_pack_end (GTK_HEADER_BAR (priv->title_box), priv->title_min_button); - g_signal_connect (priv->title_min_button, "clicked", - G_CALLBACK (gtk_window_title_min_clicked), window); - - priv->title_max_button = gtk_button_new_with_label ("\342\226\253"); - gtk_widget_set_can_focus (priv->title_max_button, FALSE); - gtk_header_bar_pack_end (GTK_HEADER_BAR (priv->title_box), priv->title_max_button); - g_signal_connect (priv->title_max_button, "clicked", - G_CALLBACK (gtk_window_title_max_clicked), window); - - priv->title_close_button = gtk_button_new_with_label ("×"); - gtk_widget_set_can_focus (priv->title_close_button, FALSE); - gtk_header_bar_pack_end (GTK_HEADER_BAR (priv->title_box), priv->title_close_button); - g_signal_connect (priv->title_close_button, "clicked", - G_CALLBACK (gtk_window_title_close_clicked), window); - gtk_widget_show_all (priv->title_box); update_window_buttons (window); -- 2.30.2